package abg.core.service.mt.impl;


import abg.core.common.cache.Cache;
import abg.core.common.message.RedisMsgType;
import abg.core.common.security.AuthKit;
import abg.core.common.security.AuthUser;
import abg.core.common.util.*;
import abg.core.domain.db.*;
import abg.core.domain.mt.MtRoomVo;
import abg.core.domain.search.Psh;
import abg.core.domain.sys.MSG;
import abg.core.domain.sys.ServiceException;
import abg.core.mapper.*;
import abg.core.service.mt.MtRoomService;
import com.alibaba.fastjson2.JSONObject;
import com.freewayso.image.combiner.ImageCombiner;
import com.freewayso.image.combiner.enums.OutputFormat;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static abg.core.domain.db.table.MtRoomInOutTableDef.MT_ROOM_IN_OUT;
import static abg.core.domain.db.table.MtRoomTableDef.MT_ROOM;
import static abg.core.domain.db.table.MtRoomUserAuthTableDef.MT_ROOM_USER_AUTH;
import static abg.core.domain.db.table.SysUserTableDef.SYS_USER;
import static com.mybatisflex.core.query.QueryMethods.count;
import static com.mybatisflex.core.query.QueryMethods.distinct;

/**
 * 会议室相关功能服务类
 */
@Slf4j
@Service
public class MtRoomServiceImpl implements MtRoomService {
    @Resource
    private Cache<String> cache;

    @Resource
    private MtRoomMapper mtRoomMapper;

    @Resource
    private MtRoomApplyMapper mtRoomApplyMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private MtRoomInOutMapper inOutMapper;

    @Resource
    private MtRoomUserAuthMapper roomUserAuthMapper;

    @Resource
    private MtLiveRoomServiceImpl mtLiveRoomService;

    //开启会议
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MtRoom openMtRoom(MtRoom param) {
        AuthUser authUser = AuthKit.mastLogin();
        String currentUserId = authUser.getUserId();
        if (currentUserId == null) throw new ServiceException(MSG.MAST_LOGIN);

        //是否有资格开会
        SysUser sysUser = sysUserMapper.selectOneById(currentUserId);
        if (!"1".equals(sysUser.getMtAuth())) throw new ServiceException(MSG.USER_MT_NO_AUTH);

        //不存在开启中的会议时才允许创建会议,会议已存在，抛出异常
        QueryWrapper query = QueryWrapper.create().where(MT_ROOM.USER_ID.eq(currentUserId)).where(MT_ROOM.MEETING_STATUS.eq("0")).orderBy(MT_ROOM.ID.desc()).limit(1);
        MtRoom queryOne = mtRoomMapper.selectOneByQuery(query);
        if (queryOne != null) throw new ServiceException(MSG.MT_ROOM_EXISTS);

        //创建会议
        MtRoom mtRoom = new MtRoom();
        mtRoom = ObjectKit.copyTo(param, mtRoom, "title", "content", "passInUserIds", "inPassword", "isBeforeIn", "inType", "isInMute");
        mtRoom.setUserId(currentUserId);
        mtRoom.setId(IdKit.getId());
        mtRoom.setMtCode(sysUser.getMtCode());
        mtRoom.setOpenTime(LocalDateTime.now());
        mtRoom.setMeetingStatus("0");
        //设置最后一条的 CloseSettingTimme
        MtRoomApply mtRoomApply = mtRoomApplyMapper.getCloseSettingTime(mtRoom.getUserId());
        mtRoom.setUserMaxCount(mtRoomApply.getUserMaxCount());

        long duration = (long) (mtRoomApply.getApplyCloseTime().doubleValue() * 60);
        LocalDateTime applyCloseTime = LocalDateTime.now().plusMinutes(duration);
        mtRoom.setCloseSettingTime(applyCloseTime);

        if (StringKit.isBlank(param.getTitle())) mtRoom.setTitle(sysUser.getAccount() + "的会议室");
        mtRoomMapper.insertSelective(mtRoom);

        //添加房主信息
        MtRoomUserAuth mtRoomUserAuth = new MtRoomUserAuth();
        mtRoomUserAuth.setAuthTop("1");
        mtRoomUserAuth.setIsCompere("1");
        mtRoomUserAuth.setMtNickName("主持人");
        mtRoomUserAuth.setMtId(mtRoom.getId());
        mtRoomUserAuth.setUserId(sysUser.getId());
        sysUser = sysUserMapper.selectColumnById(mtRoomUserAuth.getUserId(), "id", "nick_name", "avatar");
        mtRoomUserAuth.setMtNickName(sysUser.getNickName());
        mtRoomUserAuth.setMtNickAvatar(sysUser.getAvatar());

        //生成流地址
        LocalDateTime closeSettingTime = mtRoom.getCloseSettingTime();
        LocalDateTime now = LocalDateTime.now();
        long liveSecond = LocalDateKit.subSecond(closeSettingTime, now);
        //已超时
        if (liveSecond <= 0) throw new ServiceException(MSG.USER_MT_NO_AUTH);

        //生成Token
        String rtmpUrl = mtLiveRoomService.createRtmpUrlAndSaveToken(mtRoom.getId(), mtRoom.getUserId(), liveSecond);
        mtRoomUserAuth.setRtmpPushUrl(rtmpUrl);
        mtRoomUserAuth.setRtmpPullUrl(rtmpUrl);
        mtRoom.setPushUrl(rtmpUrl);

        //插入房主信息
        roomUserAuthMapper.insertSelective(mtRoomUserAuth);

        //更新用户会议截止时间
        SysUser updateUser = new SysUser();
        updateUser.setId(sysUser.getId());
        updateUser.setMtAuthCloseTime(applyCloseTime);
        sysUserMapper.update(updateUser);

        return mtRoom;
    }

    @Override
    public JSONObject createMtLinkQrCode(String mtId) {
        MtRoom mtRoom = mtRoomMapper.selectOneById(mtId);
        String userId = AuthKit.mastLogin().getUserId();
        SysUser sysUser = sysUserMapper.selectOneById(userId);

        String contents = "https://api-buyer.lvtian.info/tohome/" +
                "?type=inMt" + "&" +
                "pid=" + sysUser.getLtId() + "&" +
                "mtCode=" + mtRoom.getMtCode();

        BarcodeFormat barcodeFormat = BarcodeFormat.QR_CODE;
        Integer margin = 2;
        ErrorCorrectionLevel errorLevel = ErrorCorrectionLevel.L;
        String format = "png";
        int width = 200;
        int height = 200;
        String saveImgFilePath = "mtCode_" + sysUser.getLtId() + ".png";

        boolean success = QrCodeKit.encode(contents, barcodeFormat, margin, errorLevel, format, width, height, saveImgFilePath);
        JSONObject res = new JSONObject();
        if (success) {
            // 读取生成的二维码文件并转换为Base64字符串
            Path qrCodePath = null;
            File qrCodeFile = null;
            try {
                qrCodeFile = new File(saveImgFilePath);

                //合成器（指定背景图和输出格式，整个图片的宽高和相关计算依赖于背景图，所以背景图的大小是个基准）
                ImageCombiner combiner = new ImageCombiner(270, 310, Color.WHITE, OutputFormat.PNG);
                //设置整图圆角（输出格式必须为PNG）
                combiner.setCanvasRoundCorner(100);

                //加图片元素
                BufferedImage qrCodeImage = ImageIO.read(qrCodeFile);
                combiner.addImageElement(qrCodeImage, 30, 35);

                //加文本元素
                combiner.addTextElement("会议号:" + mtRoom.getMtCode(), 20, 80, 260).setCenter(true);

                //执行图片合并
                BufferedImage mtCodeImg = combiner.combine();
                res.put("mtCodeImg", ImageKit.bufferedImageToBase64(mtCodeImg));

                // 删除生成的二维码文件
                qrCodePath = qrCodeFile.toPath();
                Files.delete(qrCodePath);

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (qrCodeFile != null && qrCodeFile.exists()) qrCodeFile.delete();
                    if (qrCodePath != null) Files.delete(qrCodePath);
                } catch (Exception ignore) {
                }
            }
        }
        return res;
    }

    //    加入会议,并记录日志
    @Override
    public MtRoom inMtRoom(String mtCode, String inPassword) {
        AuthUser currentUser = AuthKit.mastLogin();
        SysUser inUser = sysUserMapper.selectColumnById(currentUser.getUserId(), "nick_name", "mt_auth");

        //查询进行中的会议
        QueryWrapper wrapper = QueryWrapper.create().where(MT_ROOM.MT_CODE.eq(mtCode)).and(MT_ROOM.MEETING_STATUS.eq("0"));
        MtRoom mtRoom = mtRoomMapper.selectOneByQuery(wrapper);
        if (mtRoom == null) throw new ServiceException(MSG.MT_ROOM_IS_CLOSE);

        //检查是否被禁会
        boolean isDisableInMt = roomUserAuthMapper.getIsDisableInMt(currentUser.getUserId(), mtRoom.getId());
        if (isDisableInMt) throw new ServiceException(MSG.MT_ROOM_IS_OUT);

        //检查是否需要密码
        if (StringKit.isNotBlank(inPassword) && !inPassword.equals(mtRoom.getInPassword()))
            throw new ServiceException(MSG.MT_ROOM_PASSWORD_ERROR);

        //检查是否为部分人可加入,是否在允许加入列表中
        String inType = mtRoom.getInType();
        if ("1".equals(inType)) {
            ArrayList<String> split = StringKit.split(mtRoom.getPassInUserIds());
            if (!split.contains(currentUser.getUserId())) throw new ServiceException(MSG.MT_ROOM_NO_ACCESS);
        }

        //检查主持人是否在会
        String compereStatus = mtRoom.getCompereStatus();
        String isBeforeIn = mtRoom.getIsBeforeIn();
        if ("1".equals(compereStatus) && "1".equals(isBeforeIn)) throw new ServiceException(MSG.MT_ROOM_NOT_BEFORE_IN);

        //非主持人，需要检查当前人数与最大限制是否满足
        if (!currentUser.getUserId().equals(mtRoom.getUserId())) {
//            ConcurrentSkipListSet<Channel> channels = TextHandler.mtAll.get(mtRoom.getId());
//            int userMaxCount = mtRoom.getUserMaxCount();
//            long nowUserCount = channels.size();
            long roomNowUserCount = roomUserAuthMapper.getRoomNowUserCount(mtRoom.getId());
            //不算房主
            if (roomNowUserCount > mtRoom.getUserMaxCount()) throw new ServiceException(MSG.MT_ROOM_COUNT_MAX);
        }

        //异步插入进入会议室记录
        ThreadKit.getPool().execute(() -> {
            MtRoomInOut mtRoomInOut = new MtRoomInOut();
            mtRoomInOut.setInTime(LocalDateTime.now());
            mtRoomInOut.setUserId(currentUser.getUserId());
            mtRoomInOut.setMtRoomId(mtRoom.getId());
            inOutMapper.insertSelective(mtRoomInOut);
        });

        //初始化会议室内人员信息
        ThreadKit.getPool().execute(() -> {
            //首次进入，插入会议室内人员信息
            MtRoomUserAuth mtRoomUserAuth = roomUserAuthMapper.getByMtIdAndUserId(mtRoom.getId(), currentUser.getUserId());
            if (mtRoomUserAuth == null) {
                mtRoomUserAuth = new MtRoomUserAuth();
                mtRoomUserAuth.setUserId(currentUser.getUserId());
                mtRoomUserAuth.setMtId(mtRoom.getId());
                mtRoomUserAuth.setMtNickName(inUser.getNickName());
                mtRoomUserAuth.setMtNickAvatar(inUser.getAvatar());
                roomUserAuthMapper.insertSelective(mtRoomUserAuth);
            }
        });

        return mtRoom;
    }

    //查询我开启的会议
    @Override
    public List<MtRoom> myLiveRoomPage() {
        AuthUser currentUser = AuthKit.mastLogin();
        //查询进行中的会议
        QueryWrapper wrapper = QueryWrapper.create()
                .select(MT_ROOM.ALL_COLUMNS)
                .leftJoin(MT_ROOM).on(MT_ROOM_USER_AUTH.MT_ID.eq(MT_ROOM.ID))
                .and(MT_ROOM_USER_AUTH.USER_ID.eq(currentUser.getUserId()))
                .and(MT_ROOM.MEETING_STATUS.eq("0"));
        List<MtRoom> mtRooms = roomUserAuthMapper.selectListByQueryAs(wrapper, MtRoom.class);
        return mtRooms;
    }

    @Override
    public Page<MtRoomVo> page(MtRoomVo mtRoom, Psh psh) {
        QueryWrapper wrapper = QueryWrapper.create().select(MT_ROOM.ALL_COLUMNS)
                .from(MtRoom.class)
                .leftJoin(SysUser.class)
                .on(MT_ROOM.USER_ID.eq(SYS_USER.ID))
                .select(SYS_USER.ACCOUNT, SYS_USER.PHONE, SYS_USER.ID_CARD_NAME)
                // 根据 会议ID 查询
                .and(MT_ROOM.ID.eq(mtRoom.getId()))
                // 根据 会议号 查询
                .and(MT_ROOM.MT_CODE.eq(mtRoom.getMtCode()))
                // 根据主持人账号查询
                .and(SYS_USER.ACCOUNT.eq(mtRoom.getAccount()))
                // 根据主持人手机号查询
                .and(SYS_USER.PHONE.eq(mtRoom.getPhone()))
                // 根据主持人身份证姓名查询
                .and(SYS_USER.ID_CARD_NAME.eq(mtRoom.getIdCardName()))
                // 根据状态查询
                .and(MT_ROOM.MEETING_STATUS.eq(mtRoom.getMeetingStatus()))
                // 创建时间倒序
                .orderBy(MT_ROOM.CT.desc());
        Page<MtRoomVo> page = mtRoomMapper.paginateAs(psh, wrapper, MtRoomVo.class);

        for (int i = 0; i < page.getRecords().size(); i++) {
            // 当前在线人数
            page.getRecords().get(i).setOnlineCount(roomUserAuthMapper.getRoomNowUserCount(page.getRecords().get(i).getId()) + "");

            // 累计在线人数
            QueryWrapper queryWrapper = QueryWrapper.create()
                    .from(MtRoomInOut.class).select(count(distinct(MT_ROOM_IN_OUT.USER_ID))).and(MT_ROOM_IN_OUT.MT_ROOM_ID.eq(page.getRecords().get(i).getId()));

            String totalOnlineCount = inOutMapper.selectOneByQueryAs(queryWrapper, String.class);

            page.getRecords().get(i).setTotalOnlineCount(totalOnlineCount);

        }

        return page;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object closeMeeting(MtRoom mtRoom) {
        SysUser sysUser = sysUserMapper.selectOneById(mtRoom.getUserId());
        mtLiveRoomService.closeMtRoomByUser(sysUser, RedisMsgType.MT_ADMIN_CLOSE);
        return true;
    }

    @Override
    public Object update(MtRoom mtRoom) {
        mtRoomMapper.update(mtRoom);
        return null;
    }
}
